﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;

using P2PLib.Client.DataModel;
using P2PLib.Client.Command;

namespace P2PLib.Client
{
    public class ClientServer
    {
        private System.Collections.Generic.List<CClientManager> clients;
        private BackgroundWorker bgListener;
        private Socket listenerSocket;
        private IPAddress serverIP;
        private int serverPort;
        private List<FileServer> fileServers;

        public ClientServer(IPAddress IP, int port)
        {
            this.serverIP = IP;
            this.serverPort = port;
            clients = new List<CClientManager>();
            fileServers = new List<FileServer>();
        }

        public void StartServer()
        {
            bgListener = new BackgroundWorker();
            bgListener.DoWork += new DoWorkEventHandler(bgListener_DoWork);
            bgListener.WorkerSupportsCancellation = true;
            bgListener.RunWorkerAsync();
            Console.WriteLine("Starting ClientServer....");
        }


        void bgListener_DoWork(object sender, DoWorkEventArgs e)
        {
            Console.WriteLine("Start listening {0}:{1}", serverIP.ToString(), serverPort);

            listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listenerSocket.Bind(new IPEndPoint(serverIP,serverPort));
            listenerSocket.Listen(100);
            while (true)
            {
                this.CreateNewCClientManager(this.listenerSocket.Accept());
            }
        }


        private void CreateNewCClientManager(Socket socket)
        {
            CClientManager newClientManager = new CClientManager(socket,fileServers);

            newClientManager.Search += new SearchEventHandler(OnSearch);
            newClientManager.RequestFile += new RequestFileEventHandler(OnRequestFile);
            newClientManager.ClientDisconnected += new ClientDisconnectedEventHandler(OnClientDisconnected);
            
            this.clients.Add(newClientManager);
        }

        /// <summary>
        /// 查找本地文件服务器，判断相应地文件服务器是否启动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private LocalFileInfo OnRequestFile(object sender, RequesFileEventArgs e)
        {
            if (this.SearchLocalFile != null)
            {
                return this.RequestFile(this, e);
            }
            return null;
        }

        /// <summary>
        /// 启动新的查找线程，查找本地共享文件，将查找结果返回给调用该方法的CClientManager
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnSearch(object sender, SearchEventArgs e)
        {
            if (this.SearchLocalFile != null)
            {
                this.SearchLocalFile(sender, e);
            }
        }


        public void OnClientDisconnected(object sender, ClientEventArgs e)
        {
            //通知其他客户端该客户端的离开
            
            this.RemoveClient((CClientManager)sender);
        }

        private bool RemoveClient(CClientManager clientManager)
        {
            lock (this)
            {
                int index = this.IndexOfClient(clientManager.IP);
                if (index != -1)
                {
                    this.clients.RemoveAt(index);
                    return true;
                }
                return false;
            }
        }

        private int IndexOfClient(IPAddress ip)
        {
            int index = -1;
            foreach (CClientManager cMngr in this.clients)
            {
                index++;
                if (cMngr.IP.Equals(ip))
                    return index;
            }
            return -1;
        }


        #region event
        public event SearchEventHandler SearchLocalFile;
        public event RequestFileEventHandler RequestFile;
        #endregion

    }
}
